home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / icon tools / iconian / sources / popup.e < prev    next >
Text File  |  1996-04-07  |  30KB  |  1,119 lines

  1. /*
  2. *          PopUpButton Gadget Class
  3. *
  4. *          Copyright ©1995 by Chad Randall  mbissaymssiK Software
  5. *          All Rights Reserved.
  6. *
  7. *          This source is released for instructional purposes ONLY.
  8. *          This source is not to be modified or altered in any way.
  9. *
  10. *          If you would like me to add a feature, or remove a bug,
  11. *          PLEASE contact me at:
  12. *
  13. *          crandall@msen.com
  14. *           -or- 
  15. *          229 S.Washington St, Manchester, Michigan 48158-9680 USA
  16. */
  17.  
  18. ->  Best viewed with a TAB size of 2
  19.  
  20. /*  Programming notes
  21. *
  22. *    Remember, in libraries, E will not allow [2,x,3,y,5,z]:LONG... so, we always
  23. *    need to build taglists/structs in memory.  I haven't found an easy way to do this
  24. *    so far... so I have a "base" list in memory, alloc space, then copy it over, and 
  25. *    finally longptr[n]:=x the variable parts.  Is there an easier way?
  26. */
  27.  
  28. OPT PREPROCESS
  29. LIBRARY 'popup.gadget',3,0,'popupgadget 1.0 (19.9.95)' IS 
  30.         initPopUpClass,
  31.         freePopUpClass,
  32.         addObjectToList,
  33.         disposeObjects,
  34.         disposeObjectNodes,
  35.         buildPalette,
  36.         disposePalette,
  37.         addTextToList
  38.  
  39. /*
  40. # define bigger(x,y) (IF x>y THEN x ELSE y)
  41. # define smaller(x,y) (IF x<y THEN x ELSE y)
  42. # define limit(x,y,z) (IF x<y THEN y ELSE (IF x<z THEN x ELSE z))
  43. */
  44.  
  45. MODULE    'diskfont'
  46. MODULE    'devices/inputevent'
  47. MODULE    'exec/memory','exec/lists','exec/nodes'
  48. MODULE    'graphics','graphics/text','graphics/gfx','graphics/rastport'
  49. MODULE    'intuition/cghooks','intuition/classes','intuition/classusr','intuition/gadgetclass',
  50.                 'intuition/icclass','intuition/imageclass','intuition/intuition','intuition/screens'
  51. MODULE    'utility','utility/tagitem'
  52.  
  53. MODULE    'amigalib/boopsi'
  54. ->MODULE    'mod/boopsi'
  55. MODULE    'amigalib/lists'
  56. MODULE    'tools/installhook'
  57.  
  58. MODULE    'gadgets/popup'
  59.  
  60. MODULE    'mod/compare'
  61.  
  62. ->MODULE    'mod/libdebug'
  63.  
  64. OBJECT puinst
  65.     window:PTR TO window            -> Window that is opened when gadget is active.
  66.     objlist:PTR TO lh                    -> Points to a exec-linked list of "objects"
  67.     numobjs:LONG                            -> Number of objects displayed...no bigger than across*down
  68.     active:LONG                                -> Currently active object.
  69.     lastactive:LONG                        -> Unused, really...
  70.     original:LONG                            -> Last active one, incase of an abort.
  71.     frameobj:PTR TO image            -> Class allocated frame obj to display bevel boxes.
  72.     gridw:LONG
  73.     gridh:LONG                    -> Size of individual boxes.  All boxes must be the same size.
  74.     across:LONG
  75.     down:LONG                    -> Number of objects across and down.
  76.     lastsent:LONG
  77.     winx:INT
  78.     winy:INT
  79.     winw:INT
  80.     winh:INT
  81.     gadgetbordertype:INT
  82.     windowbordertype:INT
  83.     arrow:INT                                    -> Specifies that the user wants a "popup arrow" drawn.
  84.     imagespacing:INT
  85.     windowspacing:INT
  86.     autosize:INT
  87.     layout:INT
  88.     centerimages:INT
  89.     centergadgetimage:INT
  90. ENDOBJECT
  91.  
  92. PROC dispatchPopUpGad(cl:PTR TO iclass, o, msg:PTR TO msg)
  93. /*
  94. *        This is the main routine, coming from input.device (mainly),
  95. *        E needs A4 setup to a global area, but installhook takes care of
  96. *        that for us.
  97. */
  98.     DEF retval=FALSE
  99.     DEF switch
  100.  
  101.     IF (utilitybase=0) THEN utilitybase:=OpenLibrary('utility.library',36)
  102.  
  103.     switch:=msg.methodid
  104.     SELECT switch
  105.     CASE OM_NEW;retval:=pu_new(cl,o,msg)
  106.     CASE OM_DISPOSE;retval:=pu_dispose(cl,o,msg)
  107.     CASE OM_SET;retval:=pu_set(cl, o, msg)
  108.     CASE OM_UPDATE;retval:=pu_set(cl,o,msg)
  109.     CASE OM_GET;retval:=pu_get(cl, o, msg)
  110. ->    CASE OM_NOTIFY;retval:=pu_notify(cl,o,msg)
  111.     CASE GM_RENDER;retval:=pu_render(cl, o, msg)
  112.     CASE GM_GOACTIVE;retval:=pu_goactive(cl,o,msg)
  113.     CASE GM_HANDLEINPUT;retval:=pu_handleinput(cl,o,msg)
  114.     CASE GM_GOINACTIVE;retval:=pu_goinactive(cl,o,msg)
  115.     DEFAULT;retval:=doSuperMethodA(cl, o, msg)
  116.     ENDSELECT
  117. ENDPROC retval
  118.  
  119. PROC pu_goinactive(cl:PTR TO iclass,o:PTR TO object,gpgi:PTR TO gpgoinactive)
  120.     DEF g:PTR TO gadget
  121.     DEF inst:PTR TO puinst
  122.     DEF retval
  123.  
  124.     retval:=doSuperMethodA(cl,o,gpgi)
  125.     g:=o
  126.     g.flags:=g.flags AND Not(GFLG_SELECTED)
  127.     inst:=INST_DATA(cl, o)
  128.     IF inst.window                        -> If we have a window opened, close it.
  129.         CloseWindow(inst.window)
  130.         inst.window:=0
  131.     ENDIF
  132.     notifyactive(cl, o, 0, gpgi.ginfo,TRUE)    -> Signal the window we are dying, and our last active was...
  133.     pu_render(cl, o, gpgi)        -> Rerender our unselected imagery.
  134. ENDPROC retval
  135.  
  136. PROC pu_handleinput(cl:PTR TO iclass,o:PTR TO object,gpi:PTR TO gpinput)
  137.     DEF g:PTR TO gadget
  138.     DEF switch,ie:PTR TO inputevent
  139.     DEF retval=GMR_MEACTIVE
  140.     DEF inst:PTR TO puinst
  141.     DEF ie_switch
  142.  
  143.     g:=o
  144.     inst:=INST_DATA(cl, o)
  145.     ie:=gpi.ievent
  146.     WHILE ((ie) AND (retval=GMR_MEACTIVE))
  147.         ie_switch:=ie.class
  148.         SELECT ie_switch
  149.         CASE IECLASS_RAWMOUSE
  150.             switch:=ie.code
  151.             IF (switch=SELECTDOWN) THEN switch:=MENUDOWN  -> Handles when we are "Activated"
  152.             IF (switch=MENUUP) THEN switch:=SELECTUP
  153.             SELECT switch
  154.             CASE SELECTUP
  155.                 checkmouse(gpi,inst,g)
  156.                 notifyactive(cl, o, 0, gpi.ginfo)
  157.                 IF (gpi.mousex < 0) OR (gpi.mousex > g.width) OR (gpi.mousey < 0) OR (gpi.mousey > g.height)
  158.                     retval:=GMR_NOREUSE OR GMR_VERIFY
  159.                 ELSE
  160.                     retval:=GMR_NOREUSE
  161.                 ENDIF
  162.             CASE MENUDOWN
  163.                 changeactive(inst,gpi.ginfo.drinfo,inst.original)
  164.                 notifyactive(cl, o, 0, gpi.ginfo)
  165.                 retval:=GMR_REUSE
  166.             DEFAULT
  167.                 checkmouse(gpi,inst,g)
  168.             ENDSELECT
  169.         CASE IECLASS_TIMER
  170.             IF (inst.window)
  171.                 checkmouse(gpi,inst,g)
  172.                 IF ((g.activation AND GACT_RELVERIFY)=0) THEN notifyactive(cl, o, OPUF_INTERIM, gpi.ginfo)
  173.             ENDIF
  174.         ENDSELECT
  175.         ie:=ie.nextevent
  176.     ENDWHILE
  177. ENDPROC retval
  178.  
  179. PROC checkmouse(gpi:PTR TO gpinput,inst:PTR TO puinst,g:PTR TO gadget)
  180.     DEF winx,winy,over,a,b
  181.     IF ((inst.window) AND (gpi.ginfo.window))
  182.         winx:=gpi.ginfo.window.leftedge-inst.winx+g.leftedge-inst.window.leftedge+gpi.mousex
  183.         winy:=gpi.ginfo.window.topedge-inst.winy+g.topedge-inst.window.topedge+gpi.mousey
  184.         IF ((winx<0) OR (winx>=inst.winw) OR (winy<0) OR (winy>=inst.winh))
  185.             changeactive(inst,gpi.ginfo.drinfo,inst.original)
  186.         ELSE
  187.             a:=(winx/inst.gridw)
  188.             b:=(winy/inst.gridh)
  189.             over:=a+(b*inst.across)
  190.             changeactive(inst,gpi.ginfo.drinfo,over)
  191.         ENDIF
  192.     ENDIF        
  193. ENDPROC
  194.  
  195. PROC changeactive(inst:PTR TO puinst,drawinfo,new)
  196.     IF (inst.active<>new)
  197.         IF ((new>=0) AND (new<=inst.numobjs))
  198.             inst.lastactive:=inst.active
  199.             inst.active:=new
  200.             updatewindow(inst,drawinfo,inst.active,inst.lastactive)
  201.         ENDIF
  202.     ENDIF
  203. ENDPROC
  204.  
  205. PROC pu_get(cl:PTR TO iclass,o:PTR TO object,opg:PTR TO opget)
  206.     DEF retval
  207.     DEF inst:PTR TO puinst
  208.     DEF switch
  209.     DEF longptr:PTR TO LONG
  210.     inst:=INST_DATA(cl,o)
  211.     switch:=opg.attrid
  212.     longptr:=opg.storage
  213.     SELECT switch
  214.     CASE PUA_ACTIVE
  215.         longptr[0]:=inst.active
  216.         retval:=TRUE
  217.     CASE PUA_NUMBEROFOBJECTS
  218.         longptr[0]:=inst.numobjs+1
  219.         retval:=TRUE
  220.     CASE PUA_ROWS
  221.         longptr[0]:=inst.down
  222.         retval:=TRUE
  223.     CASE PUA_COLUMNS
  224.         longptr[0]:=inst.across
  225.         retval:=TRUE
  226.     DEFAULT
  227.         retval:=doSuperMethodA(cl,o,opg)
  228.     ENDSELECT    
  229. ENDPROC retval
  230.  
  231. PROC pu_new(cl:PTR TO iclass,o:PTR TO object,ops:PTR TO opset)
  232.     DEF inst:PTR TO puinst
  233.     DEF object:PTR TO object
  234.  
  235.     IF (object:=doSuperMethodA(cl, o, ops))
  236.         inst:=INST_DATA(cl, object)
  237.         inst.objlist:=GetTagData(PUA_OBJECTS,0,ops.attrlist)
  238.         inst.active:=GetTagData(PUA_ACTIVE,0,ops.attrlist)
  239.         inst.arrow:=GetTagData(PUA_POPUPARROW,PUARROW_NONE,ops.attrlist)
  240.         inst.across:=bigger(GetTagData(PUA_COLUMNS,1,ops.attrlist),1)
  241.         inst.down:=bigger(GetTagData(PUA_ROWS,1,ops.attrlist),1)
  242.         inst.gadgetbordertype:=GetTagData(PUA_GADGETBORDER,-1,ops.attrlist)
  243.         inst.windowbordertype:=GetTagData(PUA_WINDOWBORDER,-1,ops.attrlist)
  244.         inst.windowspacing:=GetTagData(PUA_WINDOWSPACING,FALSE,ops.attrlist)
  245.         inst.imagespacing:=GetTagData(PUA_IMAGESPACING,FALSE,ops.attrlist)
  246.         inst.autosize:=GetTagData(PUA_AUTOGADGETRESIZE,FALSE,ops.attrlist)
  247.         inst.layout:=GetTagData(PUA_AUTOWINDOWLAYOUT,FALSE,ops.attrlist)
  248.         inst.centerimages:=GetTagData(PUA_CENTERIMAGES,TRUE,ops.attrlist)
  249.         inst.centergadgetimage:=GetTagData(PUA_CENTERGADGETIMAGE,TRUE,ops.attrlist)
  250.  
  251.         inst.frameobj:=NewObjectA(NIL,'frameiclass',[IA_RECESSED,FALSE,IA_EDGESONLY,FALSE,TAG_END])
  252.                                         /* The above is legal in an E-built library, because it is STATIC. */
  253.  
  254.         IF ((inst.objlist) AND (inst.frameobj))
  255.             layouteverything(object,inst)
  256.         ELSE
  257.             coerceMethodA(cl,o,[OM_DISPOSE,0,TAG_END]:LONG)
  258.             object:=NIL
  259.         ENDIF
  260.     ENDIF
  261. ENDPROC object
  262.  
  263. PROC layouteverything(g:PTR TO gadget,inst:PTR TO puinst)
  264.     DEF node:PTR TO imagenode,next
  265.     DEF i=0
  266.     DEF w,h,gw,gh
  267.     DEF longptr:PTR TO LONG
  268.     DEF im:PTR TO image
  269.     
  270.     inst.numobjs:=0
  271.     inst.gridw:=0
  272.     inst.gridh:=0
  273.     node:=inst.objlist.head
  274.     REPEAT
  275.         next:=node.listnode.succ
  276.         IF (next)
  277.             IF (node.object)
  278.                 w,h:=maxsize(node.object.width,node.object.height,node.frametype)
  279.                 IF (inst.imagespacing)
  280.                     w:=w+4
  281.                     h:=h+4
  282.                 ENDIF
  283.                 inst.gridw:=bigger(w,inst.gridw)
  284.                 inst.gridh:=bigger(h,inst.gridh)
  285.             ENDIF
  286.             IF (node.selobject)
  287.                 w,h:=maxsize(node.selobject.width,node.selobject.height,node.selframetype)
  288.                 IF (inst.imagespacing)
  289.                     w:=w+4
  290.                     h:=h+4
  291.                 ENDIF
  292.                 inst.gridw:=bigger(w,inst.gridw)
  293.                 inst.gridh:=bigger(h,inst.gridh)
  294.             ENDIF
  295.             inst.numobjs:=inst.numobjs+1
  296.         ENDIF
  297.         node:=next
  298.     UNTIL (next=0)
  299.     inst.numobjs:=inst.numobjs-1
  300. ->->->    inst.numobjs:=smaller(i-1,((inst.across*inst.down)-1))
  301.     node:=inst.objlist.head
  302.     REPEAT
  303.         next:=node.listnode.succ
  304.         IF (next)
  305.             IF (inst.centerimages)
  306.                 IF (node.object)
  307.                     node.private_offsetx:=(inst.gridw-node.object.width)/2
  308.                     node.private_offsety:=(inst.gridh-node.object.height)/2
  309.                 ENDIF
  310.                 IF (node.selobject)
  311.                     node.private_sel_offsetx:=((inst.gridw-node.selobject.width)/2)
  312.                     node.private_sel_offsety:=((inst.gridh-node.selobject.height)/2)
  313.                 ENDIF
  314.             ELSE
  315.                 w:=0
  316.                 h:=0
  317.                 gw:=0
  318.                 gh:=0
  319.                 IF (node.frametype>=0) THEN    w,h:=maxsize(0,0,node.frametype)
  320.                 IF (node.selobject)
  321.                     IF (node.selframetype>=0) THEN gw,gh:=maxsize(0,0,node.selframetype)
  322.                 ENDIF
  323.                 node.private_offsetx:=w/2
  324.                 node.private_offsety:=h/2
  325.                 node.private_sel_offsetx:=gw/2
  326.                 node.private_sel_offsety:=gh/2
  327.             ENDIF
  328.         ENDIF
  329.         node:=next
  330.     UNTIL (next=0)
  331.     gw:=0
  332.     gh:=0
  333.     IF (inst.autosize)
  334.         IF (g.gadgetrender<>0)
  335.             im:=g.gadgetrender
  336.             gw:=im.width
  337.             gh:=im.height
  338.             IF (g.selectrender<>0)
  339.                 im:=g.selectrender
  340.                 gw:=bigger(gw,im.width)
  341.                 gh:=bigger(gh,im.height)
  342.             ENDIF
  343.         ELSE
  344.             gw:=inst.gridw
  345.             gh:=inst.gridh
  346.         ENDIF
  347.         IF (inst.gadgetbordertype>=0)
  348.             gw,gh:=maxsize(gw,gh,inst.gadgetbordertype)
  349.         ENDIF
  350.         IF (inst.arrow=PUARROW_POPUP)
  351.             gw:=gw+16
  352.         ENDIF
  353.         longptr:=New(64)
  354.         longptr[0]:=GA_WIDTH
  355.         longptr[1]:=gw
  356.         longptr[2]:=GA_HEIGHT
  357.         longptr[3]:=gh
  358.         longptr[4]:=TAG_END
  359.         SetAttrsA(g,longptr)
  360.         Dispose(longptr)
  361.     ENDIF
  362. ENDPROC
  363.  
  364. PROC pu_dispose(cl:PTR TO iclass,o:PTR TO object,msg:PTR TO msg)
  365.     DEF inst:PTR TO puinst
  366.     inst:=INST_DATA(cl,o)
  367.     IF inst.window
  368.         CloseWindow(inst.window)
  369.         inst.window:=0
  370.     ENDIF
  371.     IF inst.frameobj
  372.         DisposeObject(inst.frameobj)
  373.         inst.frameobj:=0
  374.     ENDIF
  375.     RETURN doSuperMethodA(cl,o,msg)
  376. ENDPROC
  377.  
  378. PROC pu_set(cl:PTR TO iclass,o:PTR TO object,ops:PTR TO opset)
  379.     DEF inst:PTR TO puinst
  380.     DEF rp,tag:PTR TO tagitem
  381.     DEF retval
  382.     DEF gpr:PTR TO gprender
  383.     DEF newimagestate=0
  384.     DEF opu:PTR TO opupdate
  385.     DEF opn:PTR TO opnotify
  386.     DEF longptr:PTR TO LONG
  387.     DEF original
  388.     DEF newlayout=FALSE,ox,oy,ow,oh
  389.  
  390.     inst:=INST_DATA(cl, o)
  391.     ox:=o::gadget.leftedge
  392.     oy:=o::gadget.topedge
  393.     ow:=o::gadget.width
  394.     oh:=o::gadget.height
  395.     original:=inst.active
  396.     retval:=doSuperMethodA(cl, o, ops)
  397.     IF (ops.attrlist)
  398.         IF (tag:=FindTagItem(GA_DISABLED,ops.attrlist)) THEN newimagestate:=TRUE
  399.         IF (tag:=FindTagItem(GA_IMAGE,ops.attrlist))
  400.             newimagestate:=TRUE
  401.             newlayout:=TRUE
  402.         ENDIF
  403.         IF (tag:=FindTagItem(GA_SELECTRENDER,ops.attrlist))
  404.             newimagestate:=TRUE
  405.             newlayout:=TRUE
  406.         ENDIF
  407.         IF (tag:=FindTagItem(PUA_ACTIVE,ops.attrlist))
  408.             inst.active:=limit(tag.data,0,inst.numobjs)
  409.             IF (inst.active<>original) THEN newimagestate:=TRUE
  410.         ENDIF
  411.         IF (tag:=FindTagItem(PUA_ROWS,ops.attrlist))
  412.             inst.down:=tag.data
  413.         ENDIF
  414.         IF (tag:=FindTagItem(PUA_COLUMNS,ops.attrlist))
  415.             inst.across:=tag.data
  416.         ENDIF
  417.         IF (tag:=FindTagItem(PUA_AUTOGADGETRESIZE,ops.attrlist))
  418.             inst.autosize:=tag.data
  419.         ENDIF
  420.         IF (tag:=FindTagItem(PUA_WINDOWSPACING,ops.attrlist))
  421.             inst.windowspacing:=tag.data
  422.         ENDIF
  423.         IF (tag:=FindTagItem(PUA_IMAGESPACING,ops.attrlist))
  424.             inst.imagespacing:=tag.data
  425.             newlayout:=TRUE
  426.         ENDIF
  427.         IF (tag:=FindTagItem(PUA_WINDOWBORDER,ops.attrlist))
  428.             inst.windowbordertype:=tag.data
  429.         ENDIF
  430.         IF (tag:=FindTagItem(PUA_GADGETBORDER,ops.attrlist))
  431.             inst.gadgetbordertype:=tag.data
  432.             newlayout:=TRUE
  433.             newimagestate:=TRUE
  434.         ENDIF
  435.         IF (tag:=FindTagItem(PUA_CENTERGADGETIMAGE,ops.attrlist))
  436.             inst.centergadgetimage:=tag.data
  437.             newimagestate:=TRUE
  438.             newlayout:=TRUE
  439.         ENDIF
  440.         IF (tag:=FindTagItem(PUA_POPUPARROW,ops.attrlist))
  441.             inst.arrow:=tag.data
  442.             newlayout:=TRUE
  443.             newimagestate:=TRUE
  444.         ENDIF
  445.         IF (tag:=FindTagItem(PUA_CENTERIMAGES,ops.attrlist))
  446.             inst.centerimages:=tag.data
  447.             newlayout:=TRUE
  448.             newimagestate:=TRUE
  449.         ENDIF
  450.         IF (newlayout) THEN layouteverything(o,inst)
  451.         IF ((ox<>o::gadget.leftedge) OR (oy<>o::gadget.topedge) OR (ow<>o::gadget.width) OR (oh<>o::gadget.height))
  452.             rp:=ObtainGIRPort(ops.ginfo)
  453.             IF (rp)
  454.                 EraseRect(rp,ox,oy,ox+ow-1,oy+oh-1)
  455.                 ReleaseGIRPort(rp)
  456.             ENDIF
  457.             newimagestate:=TRUE
  458.         ENDIF
  459.         IF (newimagestate)
  460. ->            IF (IF (ops.methodid=OM_UPDATE) THEN (IF (ops::opupdate.flags<>OPUF_INTERIM) THEN TRUE ELSE FALSE) ELSE TRUE)
  461.                 retval:=1                            -> Notify app a visual change will take place.
  462.                 rp:=ObtainGIRPort(ops.ginfo)
  463.                 IF (rp)
  464.                     NEW gpr
  465.                     gpr.methodid:=GM_RENDER
  466.                     gpr.ginfo:=ops.ginfo
  467.                     gpr.rport:=rp
  468.                     gpr.redraw:=GREDRAW_UPDATE
  469.                     doMethodA(o,gpr)
  470.                     ReleaseGIRPort(rp)
  471.                     END gpr
  472.                 ENDIF
  473. ->            ENDIF
  474.             opn:=New(64)
  475.             longptr:=New(64)
  476.             longptr[0]:=TAG_END
  477.             opn.methodid:=OM_NOTIFY
  478.             opn.attrlist:=longptr
  479.             opn.ginfo:=ops.ginfo
  480.             opn.flags:=0
  481.             doMethodA(o,opn)
  482.             Dispose(opn)
  483.             Dispose(longptr)
  484.             ->            notifyactive(cl, o, 0, ops.ginfo)
  485.         ENDIF
  486.     ENDIF
  487. ENDPROC retval
  488.  
  489.  
  490. /*
  491. PROC pu_notify(cl:PTR TO iclass, o:PTR TO object, opu:PTR TO opupdate)
  492.     DEF retval
  493.     DEF longptr:PTR TO LONG
  494.     DEF inst:PTR TO puinst
  495.     DEF opn:PTR TO opnotify
  496.  
  497.     inst:=INST_DATA(cl,o)
  498.     longptr:=New(64)
  499.     longptr[0]:=GA_ID
  500.     longptr[1]:=o::gadget.gadgetid
  501.     longptr[2]:=PUA_ACTIVE
  502.     longptr[3]:=inst.active
  503.     IF (opu.attrlist=NIL)
  504.         longptr[4]:=TAG_END
  505.     ELSE
  506.         longptr[4]:=TAG_MORE
  507.         longptr[5]:=opu.attrlist
  508.     ENDIF
  509.     opn:=New(64)
  510.     opn.methodid:=OM_NOTIFY
  511.     opn.attrlist:=longptr
  512.     opn.ginfo:=opu.ginfo
  513.     opn.flags:=opu.flags
  514.     opn.flags:=0
  515.     retval:=doSuperMethodA(cl,o,opn)
  516.     Dispose(opn)
  517.     Dispose(longptr)
  518. ENDPROC retval
  519. */
  520.  
  521. PROC pu_goactive(cl:PTR TO iclass, o:PTR TO object, gpi:PTR TO gpinput)
  522.     DEF retval=GMR_MEACTIVE
  523.     DEF rp:PTR TO rastport
  524.     DEF inst:PTR TO puinst
  525.     DEF gi:PTR TO gadgetinfo
  526.     DEF g:PTR TO gadget
  527.     DEF left,top,midx,midy
  528.     DEF width,height
  529.     DEF gprender:PTR TO gprender
  530.     DEF longptr:PTR TO LONG
  531.  
  532.     g:=o
  533.     gi:=gpi.ginfo
  534.     inst:=INST_DATA(cl, g)
  535.     IF (g.flags AND GFLG_DISABLED) THEN RETURN GMR_NOREUSE
  536.     doSuperMethodA(cl,o,gpi)
  537. ->    IF (gpi.ievent)
  538.         g.flags:=g.flags OR GFLG_SELECTED
  539.         IF (rp:=ObtainGIRPort(gi))
  540.  
  541.             NEW gprender
  542.             gprender.methodid:=GM_RENDER
  543.             gprender.ginfo:=gi
  544.             gprender.rport:=rp
  545.             gprender.redraw:=GREDRAW_UPDATE
  546.             doMethodA(o,gprender)
  547.             END gprender
  548.  
  549.             ReleaseGIRPort(rp)
  550.  
  551.             IF ((inst.window=0) AND (gi.window))
  552.                 inst.winw:=(inst.across*inst.gridw)
  553.                 inst.winh:=(inst.down*inst.gridh)
  554.                 width,height:=maxsize(inst.winw,inst.winh,inst.windowbordertype)
  555.                 IF (inst.windowspacing)
  556.                     width:=width+4
  557.                     height:=height+4
  558.                 ENDIF
  559.                 inst.winx:=((width-inst.winw)/2)
  560.                 inst.winy:=((height-inst.winh)/2)
  561.                 midx:=gpi.mousex-((g.width/2)+(IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0))
  562.                 midy:=gpi.mousey-(g.height/2)
  563.                 left:=(((gi.window.leftedge+g.leftedge+(g.width/2))-((inst.active - ((inst.active/inst.across)*inst.across)) * inst.gridw) - (inst.gridw/2))-inst.winx) +(IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0)+midx
  564.                 top:=((gi.window.topedge+g.topedge+(g.height/2))-((inst.active/inst.across)*inst.gridh) - (inst.gridh/2))-inst.winy+midy
  565.                 longptr:=New(240)
  566.                 CopyMem({deftags},longptr,90)
  567.                 longptr[1]:=left
  568.                 longptr[3]:=top
  569.                 longptr[5]:=width
  570.                 longptr[7]:=height
  571.                 longptr[9]:=gi.screen
  572.                 inst.window:=OpenWindowTagList(0,longptr)    -> We cannot use [tags]:LONG because this is a library!
  573.                 Dispose(longptr)
  574.                 inst.lastactive:=-1
  575.                 inst.original:=inst.active
  576.                 updatewindow(inst,gpi.ginfo.drinfo,-1,-1)
  577.                 IF (inst.windowbordertype>=0)
  578.                     IF inst.window
  579.                         longptr:=New(64)
  580.                         CopyMem({frametaglist},longptr,64)
  581.                         longptr[1]:=width
  582.                         longptr[3]:=height
  583.                         longptr[5]:=FALSE
  584.                         longptr[7]:=inst.windowbordertype
  585.                         SetAttrsA(inst.frameobj,longptr)
  586.                         Dispose(longptr)
  587.                          DrawImageState(inst.window.rport,inst.frameobj,0,0,IDS_NORMAL,gpi.ginfo.drinfo)
  588.                      ENDIF
  589.                 ENDIF
  590.             ENDIF
  591.             retval:=GMR_MEACTIVE
  592.         ENDIF
  593. ->    ELSE
  594. ->        retval:=GMR_NOREUSE
  595. ->    ENDIF
  596. ENDPROC retval
  597.  
  598. PROC updatewindow(inst:PTR TO puinst,drawinfo:PTR TO drawinfo,updatethisone,andthisone)
  599.     DEF xx,yy
  600.     DEF node:PTR TO imagenode
  601.     DEF next
  602.     DEF cur
  603.     IF inst.window=0 THEN RETURN
  604.     node:=inst.objlist.head
  605.     FOR yy:=0 TO (inst.down-1)
  606.         FOR xx:=0 TO (inst.across-1)
  607.             next:=node.listnode.succ
  608.             IF (next)
  609.                 cur:=(yy*inst.across)+xx
  610.                 node.private_lastdrawn:=IF (inst.active=cur) THEN TRUE ELSE FALSE
  611.                 IF ((updatethisone=-1) OR (updatethisone=cur) OR (andthisone=cur))
  612.                     drawnode(inst.window.rport,inst.winx+(xx*inst.gridw),inst.winy+(yy*inst.gridh),inst.gridw,inst.gridh,node,inst,drawinfo,node.private_lastdrawn)
  613.                 ENDIF
  614.                 node:=next
  615.             ENDIF
  616.         ENDFOR
  617.     ENDFOR 
  618.     inst.lastactive:=inst.active
  619. ENDPROC
  620.  
  621. PROC drawnode(rast,x,y,w,h,node:PTR TO imagenode,inst:PTR TO puinst,drawinfo:PTR TO drawinfo,sel)
  622.     DEF obj,ids=IDS_NORMAL,offx,offy
  623.     DEF longptr:PTR TO LONG,frame
  624.     IF (node)
  625.         SetAPen(rast,drawinfo.pens[IF sel THEN node.selfillcolor ELSE BACKGROUNDPEN])
  626.         RectFill(rast,x,y,(x+w-1),(y+h-1))
  627.         obj:=node.object
  628.         offx:=node.private_offsetx
  629.         offy:=node.private_offsety
  630.         frame:=node.frametype
  631.         IF (sel)
  632.             frame:=node.selframetype
  633.             IF node.selobject
  634.                 obj:=node.selobject
  635.                 offx:=node.private_sel_offsetx
  636.                 offy:=node.private_sel_offsety
  637.             ELSE
  638.                 ids:=IDS_SELECTED
  639.             ENDIF
  640.         ENDIF
  641.         IF (frame>=0)
  642.             longptr:=New(64)
  643.             CopyMem({frametaglist},longptr,64)
  644.             longptr[1]:=w
  645.             longptr[3]:=h
  646.             longptr[5]:=IF (sel) THEN TRUE ELSE FALSE
  647.             longptr[7]:=frame
  648.             SetAttrsA(inst.frameobj,longptr)
  649.             Dispose(longptr)
  650.              DrawImageState(rast,inst.frameobj,x,y,IDS_NORMAL,drawinfo)
  651.         ENDIF
  652.         DrawImageState(rast,obj,x+offx,y+offy,ids,drawinfo)
  653.     ENDIF
  654. ENDPROC
  655.  
  656. frametaglist:
  657.     LONG    IA_WIDTH,0,
  658.                 IA_HEIGHT,0,
  659.                 IA_RECESSED,0,
  660.                 IA_FRAMETYPE,0,
  661.                 IA_EDGESONLY,TRUE,
  662.                 IA_BGPEN,0,
  663.                 IA_FGPEN,0,
  664.                 TAG_END
  665.  
  666. PROC maxsize(bw,bh,frametype)
  667. -> Used to be: PROC maxsize(inst:PTR TO puinst,o1:PTR TO image,frametype,drawinfo)
  668. ->    DEF framebox:PTR TO impframebox
  669. ->    DEF fbox:PTR TO ibox
  670. ->    DEF cbox:PTR TO ibox
  671.     DEF aw=0,ah=0
  672.  
  673.     SELECT frametype
  674.     CASE FRAME_DEFAULT;aw:=2;ah:=2
  675.     CASE FRAME_BUTTON;aw:=4;ah:=2
  676.     CASE FRAME_RIDGE;aw:=8;ah:=4
  677.     CASE FRAME_ICONDROPBOX;aw:=12;ah:=6
  678.     ENDSELECT
  679.     bw:=bw+aw
  680.     bh:=bh+ah
  681.  
  682. /*
  683.  
  684. * Unfortunatly, frameiclass always seems to return +4,+4 for it's dimensions
  685. * after giving it IM_FRAMEBOX... so, I'm deactivating this code until I discover
  686. * why...    I've tried ALOT of different things... no luck
  687.  
  688. ->        IF drawinfo=0 THEN drawinfo:=inst.drawinfo    ...PUA_DRAWINFO no longer...
  689.         IF drawinfo=0 THEN RETURN o1.width+16,o1.height+16
  690.         SetAttrsA(inst.frameobj,[IA_FRAMETYPE,frametype,IA_DOUBLEEMBOSS,TRUE,TAG_END])
  691.         framebox:=New(64)
  692.         cbox:=New(32)
  693.         fbox:=New(32)
  694.         cbox.width:=o1.width
  695.         cbox.height:=o1.height
  696.         cbox.left:=0
  697.         cbox.top:=0
  698.         framebox.methodid:=IM_FRAMEBOX
  699.         framebox.contentsbox:=cbox
  700.         framebox.framebox:=fbox
  701.         framebox.drinfo:=drawinfo
  702.         framebox.frameflags:=0
  703.         doMethodA(inst.frameobj,framebox)
  704.         w:=bigger(o1.width,fbox.width)
  705.         h:=bigger(o1.height,fbox.height)
  706.  
  707.         Dispose(framebox)
  708.         Dispose(cbox)
  709.         Dispose(fbox)
  710. */
  711. ENDPROC bw,bh
  712.  
  713. PROC notifyactive(cl:PTR TO iclass, o:PTR TO gadget, flags, ginfo,flag=FALSE)
  714.     DEF msg:PTR TO opnotify
  715.     DEF inst:PTR TO puinst
  716.     DEF longptr:PTR TO LONG
  717.  
  718.     inst:=INST_DATA(cl, o)
  719.     IF ((inst.active<>inst.lastsent) OR (flag=TRUE))
  720.         NEW msg
  721.         longptr:=New(40)
  722.         longptr[0]:=PUA_ACTIVE
  723.         longptr[1]:=inst.active
  724.         longptr[2]:=GA_ID
  725.         longptr[3]:=o.gadgetid
  726.         longptr[4]:=TAG_END
  727.         msg.methodid:=OM_NOTIFY
  728.         msg.attrlist:=longptr
  729.         msg.ginfo:=ginfo
  730.         msg.flags:=flags
  731.         doSuperMethodA(cl,o, msg)
  732.         END msg
  733.         Dispose(longptr)
  734.     ENDIF
  735.     inst.lastsent:=inst.active
  736. ENDPROC
  737.  
  738. -> Erase and rerender the gadget.
  739. PROC pu_render(cl:PTR TO iclass, o:PTR TO object, gpr:PTR TO gprender)
  740.     DEF inst:PTR TO puinst, rp, retval=TRUE, pens:PTR TO INT
  741.     DEF g:PTR TO gadget
  742.     DEF node:PTR TO imagenode
  743.     DEF i
  744.     DEF issel
  745.     DEF shine,shadow
  746.     DEF xx,yy
  747.     DEF ox=0,oy=0
  748.     DEF longptr:PTR TO LONG,switch
  749.     DEF im:PTR TO image
  750.     DEF im2:PTR TO image
  751.  
  752.     g:=o
  753.     inst:=INST_DATA(cl, g)
  754.  
  755.     retval:=doSuperMethodA(cl,o,gpr)
  756.  
  757.     pens:=gpr.ginfo.drinfo.pens
  758.     IF gpr.methodid=GM_RENDER
  759.         rp:=gpr.rport
  760.     ELSE
  761.         rp:=ObtainGIRPort(gpr.ginfo)
  762.     ENDIF
  763.     IF (rp)
  764.         node:=inst.objlist.head
  765.         IF (inst.active>0)
  766.             FOR i:=0 TO inst.active-1
  767.                 IF (node) THEN node:=node.listnode.succ
  768.             ENDFOR
  769.         ENDIF
  770.         IF (node.listnode.succ)
  771.             issel:=(g.flags AND GFLG_SELECTED)
  772.             xx:=IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0
  773.             IF (inst.gadgetbordertype>=0)
  774.                 longptr:=New(64)
  775.                 CopyMem({frametaglist},longptr,64)
  776.                 longptr[1]:=g.width
  777.                 longptr[3]:=g.height
  778.                 longptr[5]:=IF (issel) THEN TRUE ELSE FALSE
  779.                 longptr[7]:=inst.gadgetbordertype
  780.                 longptr[9]:=FALSE
  781.                 SetAttrsA(inst.frameobj,longptr)
  782.                 Dispose(longptr)
  783.                 DrawImageState(rp,inst.frameobj,g.leftedge,g.topedge,IDS_NORMAL,gpr.ginfo.drinfo)
  784.                 ox,oy:=maxsize(0,0,inst.gadgetbordertype)
  785.                 ox:=ox/2
  786.                 oy:=oy/2
  787.              ELSE
  788.                 SetAPen(rp,pens[BACKGROUNDPEN])
  789.                 SetDrMd(rp,RP_JAM2)
  790.                 RectFill(rp,g.leftedge,g.topedge,g.leftedge+g.width,g.topedge+g.height)
  791.              ENDIF
  792.             im:=g.gadgetrender
  793.             IF ((issel) AND (g.selectrender<>0)) THEN im:=g.selectrender
  794.             IF (inst.centergadgetimage=FALSE) THEN ox:=ox+(xx*2)
  795.             IF (im)
  796.                 IF (inst.centergadgetimage)
  797.                     ox:=((g.width-im.width)/2)+xx
  798.                     oy:=((g.height-im.height)/2)
  799.                 ENDIF
  800.                  DrawImageState(rp,im,g.leftedge+ox,g.topedge+oy,IF (issel) THEN IDS_SELECTED ELSE IDS_NORMAL,gpr.ginfo.drinfo)
  801.             ELSE
  802.                 IF (inst.centergadgetimage)
  803.                     ox:=((g.width-inst.gridw)/2)+xx
  804.                     oy:=((g.height-inst.gridh)/2)
  805.                 ENDIF
  806.                 drawnode(rp,g.leftedge+ox,g.topedge+oy,inst.gridw,inst.gridh,node,inst,gpr.ginfo.drinfo,issel)
  807.             ENDIF
  808.  
  809.             IF (inst.arrow)
  810.                 IF (issel)
  811.                     shine:=pens[SHADOWPEN]
  812.                     shadow:=pens[SHINEPEN]
  813.                 ELSE
  814.                     shine:=pens[SHINEPEN]
  815.                     shadow:=pens[SHADOWPEN]
  816.                 ENDIF
  817.                 switch:=inst.arrow
  818.                 xx,yy:=maxsize(0,0,inst.gadgetbordertype)
  819.                 SELECT switch
  820.                 CASE PUARROW_POPUP
  821.                     ox:=g.leftedge+(xx/2)
  822.                     oy:=g.topedge+(yy/2)
  823.                     SetAPen(rp,shadow)
  824.                     Move(rp,ox+13,oy+1)
  825.                     Draw(rp,ox+13,oy+(g.height-yy-2))
  826.                     SetAPen(rp,shine)
  827.                     Move(rp,ox+14,oy+1)
  828.                     Draw(rp,ox+14,oy+(g.height-yy-2))
  829.                     xx:=ox+2
  830.                     yy:=g.topedge+(g.height/2)-4
  831.                     FOR ox:=xx TO xx+6 STEP 3
  832.                         FOR oy:=yy TO yy+6 STEP 3
  833.                             SetAPen(rp,shadow)
  834.                             WritePixel(rp,ox,oy)
  835.                             WritePixel(rp,ox+1,oy)
  836.                             WritePixel(rp,ox,oy+1)
  837.                             SetAPen(rp,shine)
  838.                             WritePixel(rp,ox+2,oy+1)
  839.                             WritePixel(rp,ox+2,oy+2)
  840.                             WritePixel(rp,ox+1,oy+2)
  841.                         ENDFOR
  842.                     ENDFOR
  843.                 CASE PUARROW_TINY
  844.                     xx:=g.leftedge+g.width-6-(xx/2)
  845.                     yy:=g.topedge+1+(yy/2)
  846.  
  847.                     SetAPen(rp,shadow)
  848.                     Move(rp,xx+1,yy)
  849.                     Draw(rp,xx+1,yy+6)
  850.                     Move(rp,xx+2,yy+6)
  851.                     Draw(rp,xx+5,yy+3)
  852.  
  853.                     SetAPen(rp,shine)
  854.                     Move(rp,xx,yy)
  855.                     Draw(rp,xx,yy+6)
  856.                     Move(rp,xx+2,yy+5)
  857.                     Draw(rp,xx+2,yy)
  858.                     Draw(rp,xx+5,yy+3)
  859.  
  860.                     SetAPen(rp,pens[BACKGROUNDPEN])
  861.                     Move(rp,xx+3,yy+2)
  862.                     Draw(rp,xx+3,yy+4)
  863.                     Draw(rp,xx+4,yy+3)
  864.                 ENDSELECT
  865.             ENDIF
  866.         ENDIF
  867.         IF (g.flags AND GFLG_DISABLED)
  868.             SetAPen(rp,pens[TEXTPEN])
  869.             SetDrMd(rp,RP_JAM1)
  870.             setafpt(rp,[%10001000100010000010001000100010],1)
  871.             RectFill(rp,g.leftedge,g.topedge,g.leftedge+g.width-1,g.topedge+g.height-1)
  872.         ENDIF
  873.         IF (gpr.methodid<>GM_RENDER) THEN ReleaseGIRPort(rp)
  874.     ELSE
  875.         retval:=FALSE
  876.     ENDIF
  877. ENDPROC retval
  878.  
  879. PROC setafpt(rast:PTR TO rastport,pattern,size)
  880.     rast.areaptrn:=pattern
  881.     rast.areaptsz:=size
  882. ENDPROC
  883.  
  884. deftags:
  885.     LONG    WA_LEFT,0,
  886.                 WA_TOP,0,
  887.                 WA_WIDTH,0,
  888.                 WA_HEIGHT,0,
  889.                 WA_CUSTOMSCREEN,0,
  890.                 WA_BORDERLESS,TRUE,
  891.                 WA_RMBTRAP,TRUE,
  892.                 WA_AUTOADJUST,TRUE,
  893.                 WA_ACTIVATE,FALSE,
  894.                 WA_NOCAREREFRESH,TRUE,
  895.                 WA_SIMPLEREFRESH,TRUE,
  896. ->                WA_SMARTREFRESH,TRUE,
  897.                 TAG_END,0
  898.  
  899.     CHAR 0, '$VER: popup.gadget 1.0 (11.9.95)', 0,0
  900.  
  901. PROC freePopUpClass(cl)
  902.     FreeClass(cl)
  903.     IF utilitybase
  904.         CloseLibrary(utilitybase)
  905.         utilitybase:=0
  906.     ENDIF
  907. ENDPROC
  908. PROC initPopUpClass()
  909.     DEF cl:PTR TO iclass
  910.     utilitybase:=OpenLibrary('utility.library',36)
  911. ->    IF cl:=MakeClass(NIL, 'buttongclass', NIL, SIZEOF puinst, 0)
  912.     IF cl:=MakeClass(NIL, 'gadgetclass', NIL, SIZEOF puinst, 0)
  913.         installhook(cl.dispatcher, {dispatchPopUpGad})
  914.     ENDIF
  915. ENDPROC cl
  916.  
  917. PROC addObjectToList(list,object,frametype,selobject,selframetype,selfillcolor)
  918.     DEF node:PTR TO imagenode
  919.  
  920.     node:=AllocMem(SIZEOF imagenode,MEMF_ANY OR MEMF_CLEAR)
  921.     node.object:=object
  922.     node.frametype:=frametype
  923.     node.selobject:=selobject
  924.     node.selfillcolor:=selfillcolor
  925.     node.selframetype:=selframetype
  926.     node.private_iallocated:=-4
  927.     AddTail(list,node)
  928. ENDPROC node
  929.  
  930. PROC addTextToList(list,text,textattr:PTR TO textattr,drawinfo:PTR TO drawinfo) HANDLE
  931.     DEF rast:PTR TO rastport
  932.     DEF xor=0,w=0,h=0
  933.     DEF textextent:PTR TO textextent
  934.     DEF it1:PTR TO intuitext
  935.     DEF it2:PTR TO intuitext
  936.     DEF slen,textstring=0
  937.     DEF obj1,obj2
  938.     DEF longptr:PTR TO LONG
  939.     DEF node:PTR TO imagenode
  940.     DEF mytextattr=0:PTR TO textattr
  941.     DEF textfont=0:PTR TO textfont
  942.  
  943.     mytextattr:=AllocMem(SIZEOF textattr,MEMF_ANY OR MEMF_CLEAR)
  944.     IF (textattr)
  945.         mytextattr.name:=String(StrLen(textattr.name))
  946.         StrCopy(mytextattr.name,textattr.name)
  947.         mytextattr.ysize:=textattr.ysize
  948.         mytextattr.style:=textattr.style
  949.         mytextattr.flags:=textattr.flags
  950.     ELSE
  951.         mytextattr.name:='topaz.font'
  952.         mytextattr.ysize:=8
  953.     ENDIF
  954.     diskfontbase:=OpenLibrary('diskfont.library',36)
  955.     IF (diskfontbase)
  956.         textfont:=OpenDiskFont(mytextattr)
  957.         CloseLibrary(diskfontbase)
  958.     ELSE
  959.         textfont:=OpenFont(mytextattr)
  960.     ENDIF
  961.     IF (textfont)
  962.         NEW rast,textextent
  963.         slen:=StrLen(text)
  964.         InitRastPort(rast)
  965.         xor:=xor OR (IF ((textfont.style AND 1)<>(textattr.style AND 1)) THEN 1 ELSE 0)
  966.         xor:=xor OR (IF ((textfont.style AND 2)<>(textattr.style AND 2)) THEN 2 ELSE 0)
  967.         xor:=xor OR (IF ((textfont.style AND 4)<>(textattr.style AND 4)) THEN 4 ELSE 0)
  968.         SetFont(rast,textfont)
  969.         SetSoftStyle(rast,xor,7)
  970.         TextExtent(rast,text,slen,textextent)
  971.         w:=Abs(textextent.extent.minx)+Abs(textextent.extent.maxx)+1
  972.         h:=Abs(textextent.extent.miny)+Abs(textextent.extent.maxy)+1
  973.         END rast,textextent
  974.         it1:=AllocMem(SIZEOF intuitext,MEMF_ANY OR MEMF_CLEAR)
  975.         it2:=AllocMem(SIZEOF intuitext,MEMF_ANY OR MEMF_CLEAR)
  976.         
  977.         textstring:=String(StrLen(text))
  978.         StrCopy(textstring,text,ALL)
  979.         it1.itext:=textstring
  980.         it2.itext:=textstring
  981.         it1.frontpen:=6
  982.         it1.backpen:=14
  983.         it1.drawmode:=RP_JAM1
  984.         it2.drawmode:=RP_JAM1
  985.         it1.itextfont:=mytextattr
  986.         it2.itextfont:=mytextattr
  987.  
  988.         longptr:=New(128)
  989.         CopyMem({itexttags},longptr,128)
  990.         longptr[1]:=w
  991.         longptr[3]:=h
  992.         longptr[5]:=it1
  993.         longptr[7]:=drawinfo.pens[TEXTPEN]
  994.         obj1:=NewObjectA(NIL,{itexticlass},longptr)
  995.         longptr[5]:=it2
  996.         longptr[7]:=drawinfo.pens[FILLTEXTPEN]
  997.         obj2:=NewObjectA(NIL,{itexticlass},longptr)
  998.         Dispose(longptr)
  999.  
  1000.         IF ((obj1) AND (obj2))
  1001.             node:=addObjectToList(list,obj1,-1,obj2,FRAME_BUTTON,FILLPEN)
  1002.             node.private_iallocated:=-5
  1003.             node.private_itextn:=it1
  1004.             node.private_itexts:=it2
  1005.             node.private_textfont:=textfont
  1006.             node.private_textattr:=mytextattr
  1007.             node.private_text:=textstring
  1008.         ELSE
  1009.             CloseFont(textfont)
  1010.         ENDIF
  1011.     ELSE
  1012.         Raise(-1)
  1013.     ENDIF
  1014. EXCEPT
  1015.     IF (mytextattr.name) THEN DisposeLink(mytextattr.name)
  1016.     IF (textstring) THEN DisposeLink(textstring)
  1017.     IF (mytextattr) THEN FreeMem(mytextattr,SIZEOF textattr)
  1018.     IF (textfont) THEN CloseFont(textfont)
  1019. ENDPROC node
  1020.  
  1021. itexttags:
  1022.     LONG    IA_WIDTH,0,
  1023.                 IA_HEIGHT,0,
  1024.                 IA_DATA,0,
  1025.                 IA_FGPEN,0,
  1026.                 TAG_END
  1027.  
  1028. PROC disposeObjectNodes(list:PTR TO lh)
  1029.     DEF node:PTR TO imagenode,next
  1030.     node:=list.head
  1031.     REPEAT
  1032.         next:=node.listnode.succ
  1033.         IF (next)
  1034.             IF (node.private_iallocated<-3)
  1035.                 Remove(node)
  1036.                 FreeMem(node,SIZEOF imagenode)
  1037.             ENDIF
  1038.         ENDIF
  1039.         node:=next
  1040.     UNTIL (next=0)
  1041. ENDPROC
  1042.  
  1043. PROC disposeObjects(list:PTR TO lh)
  1044.     DEF node:PTR TO imagenode,next
  1045.     node:=list.head
  1046.     REPEAT
  1047.         next:=node.listnode.succ
  1048.         IF (next)
  1049.             IF node.private_iallocated=-5            -> A ITEXTICLASS we allocated, so we dispose the IA_DATA field.
  1050.                 IF (node.private_text) THEN DisposeLink(node.private_text)
  1051.                 IF (node.private_textfont) THEN CloseFont(node.private_textfont)
  1052.                 IF (node.private_textattr) THEN FreeMem(node.private_textattr,SIZEOF textattr)
  1053.                 IF (node.private_itextn) THEN FreeMem(node.private_itextn,SIZEOF intuitext)
  1054.                 IF (node.private_itexts) THEN FreeMem(node.private_itexts,SIZEOF intuitext)
  1055.             ENDIF
  1056.             IF node.object THEN DisposeObject(node.object)
  1057.             IF node.selobject THEN DisposeObject(node.selobject)
  1058.         ENDIF
  1059.         node:=next
  1060.     UNTIL (next=0)
  1061. ENDPROC
  1062.  
  1063. PROC buildPalette(firstcolor,lastcolor,width,height)
  1064.     DEF i,obj1,obj2
  1065.     DEF list:PTR TO mlh
  1066.     DEF pal1tags
  1067.     DEF pal2tags
  1068.     list:=AllocMem(SIZEOF mlh,MEMF_ANY OR MEMF_CLEAR)
  1069.     newList(list)
  1070.  
  1071.     pal1tags:=New(64)
  1072.     pal2tags:=New(64)
  1073.     CopyMem({pal1taglist},pal1tags,60)
  1074.     CopyMem({pal2taglist},pal2tags,60)
  1075.     PutLong(pal1tags+4,width)
  1076.     PutLong(pal1tags+12,height)
  1077.     PutLong(pal2tags+4,width)
  1078.     PutLong(pal2tags+12,height)
  1079.     FOR i:=firstcolor TO lastcolor
  1080.         PutLong(pal1tags+20,i)
  1081.         PutLong(pal2tags+20,i)
  1082.         obj1:=NewObjectA(NIL,{fillrectclass},pal1tags)
  1083.         obj2:=NewObjectA(NIL,{fillrectclass},pal2tags)
  1084.         IF obj1
  1085.             IF obj2
  1086.                 addObjectToList(list,obj1,-1,obj2,1,BACKGROUNDPEN)
  1087.             ENDIF
  1088.         ENDIF
  1089.     ENDFOR            
  1090.     Dispose(pal1tags)
  1091.     Dispose(pal2tags)
  1092. ENDPROC list
  1093.  
  1094. pal1taglist:
  1095.     LONG IA_WIDTH,0,
  1096.                 IA_HEIGHT,0,
  1097.                 IA_FGPEN,0,
  1098.                 IA_MODE,RP_JAM2,
  1099.                 TAG_END
  1100. pal2taglist:
  1101.     LONG IA_WIDTH,0,
  1102.                 IA_HEIGHT,0,
  1103.                 IA_FGPEN,0,
  1104.                 IA_MODE,RP_JAM2,
  1105.                 TAG_END
  1106.  
  1107. PROC disposePalette(list)
  1108.     disposeObjects(list)
  1109.     disposeObjectNodes(list)
  1110.     FreeMem(list,SIZEOF mlh)
  1111. ENDPROC
  1112.  
  1113. PROC main() IS EMPTY
  1114.  
  1115. itexticlass:
  1116.     CHAR    'itexticlass',0
  1117. fillrectclass:
  1118.     CHAR    'fillrectclass',0
  1119.